﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using LispInterpretor.DataTypes;
using System.Numerics;

namespace UnitTests.ArithmeticTests
{
    [TestClass]
    public class TestNumber
    {
        private BigInteger Three = (BigInteger)3;
        private BigInteger Four = (BigInteger)4;

        [TestMethod]
        public void TestMultiply()
        {
            Number first = new Number(Three, BigInteger.One);
            Number second = new Number(Four, BigInteger.One);

            Number multiplication = Number.Multiply(first, second);
            Assert.AreEqual((BigInteger)12, multiplication.Numerator);
            Assert.AreEqual(BigInteger.One, multiplication.Denominator);
        }

        [TestMethod]
        public void TestSubtract()
        {
            Number first = new Number(Three, BigInteger.One);
            Number second = new Number(Four, BigInteger.One);

            Number result = Number.Subtract(first, second);

            Assert.AreEqual(BigInteger.MinusOne, result.Numerator);
            Assert.AreEqual(BigInteger.One, result.Denominator);
        }

        [TestMethod]
        public void TestDivide()
        {
            Number first = new Number(Three, BigInteger.One);
            Number second = new Number(Four, BigInteger.One);

            Number result = Number.Divide(first, second);

            Assert.AreEqual(Three, result.Numerator);
            Assert.AreEqual(Four, result.Denominator);
        }

        [TestMethod]
        public void TestParse()
        {
            string pi = "3.14159";

            Number piFract = Number.Parse(pi);

            Assert.AreEqual((BigInteger)314159, piFract.Numerator);
            Assert.AreEqual((BigInteger)100000, piFract.Denominator);
        }

        [TestMethod]
        [ExpectedException(typeof(InvalidProgramException))]
        public void TestBadParse()
        {
            Number fract = Number.Parse("Test");
        }

        [TestMethod]
        public void TestIsNumberWithInteger()
        {
            Assert.IsTrue(Number.IsNumber("12345678910"));
        }

        [TestMethod]
        public void TestIsNumberWithDecimalPoint()
        {
            Assert.IsTrue(Number.IsNumber("12345678910.12345678910"));
        }

        [TestMethod]
        public void TestIsNumberWithGarabage()
        {
            Assert.IsFalse(Number.IsNumber("Testing123Testing"));
        }
        [TestMethod]
        public void TestFractionSimplification()
        {
            Number simplifiedFraction = new Number(75, 100);

            Assert.AreEqual(Three, simplifiedFraction.Numerator);
            Assert.AreEqual(Four, simplifiedFraction.Denominator);
        }

        [TestMethod]
        public void TestFractionEqualityWithEqualValues()
        {
            Number firstNumber = new Number(75, 100);
            Number secondNumber = new Number(3, 4);

            Assert.IsTrue(firstNumber.Equals(secondNumber));
        }

        [TestMethod]
        public void TestFractionEqualityWithNoneEqualValues()
        {
            Number threeQuarters = new Number(3, 4);
            Number oneQuarter = new Number(1, 4);

            Assert.IsFalse(threeQuarters.Equals(oneQuarter));
        }

        [TestMethod]
        public void TestComparisonWithNoneIdentialTypes()
        {
            int six = 6;

            Number threeQuarters = new Number(3, 4);

            Assert.IsFalse(threeQuarters.Equals(six));
        }

        [TestMethod]
        public void TestShortDivision()
        {
            Number item = new Number(950, 4);

            Assert.AreEqual<string>("237.5",item.ToString());
        }

        [TestMethod]
        public void TestLongerDivision()
        {
            var item = new Number(7919, 7907);

            Assert.AreEqual<string>("1.00151764259516883773", item.ToString());
        }

        [TestMethod]
        public void TestValueSmallerThanOne()
        {
            var item = new Number(1, 3);

            Assert.AreEqual<string>("0.33333333333333333333", item.ToString());
        }

        [TestMethod]
        public void TestNegativeValue()
        {
            var item = new Number(-1, 3);

            Assert.AreEqual<string>("-0.33333333333333333333", item.ToString());
        }

        [TestMethod]
        public void TestZero()
        {
            var item = new Number(0, 1);

            Assert.AreEqual<string>("0", item.ToString());
        }
    }
}
